#include "widget.h"
#include "ui_widget.h"
#include <QDebug>
#include <QMouseEvent>
#include<QPaintEvent>
#include<QPainter>
#include <vector>
#include<Eigen/Core>
#include<Eigen/Dense>

using namespace std;


const double eps = 1e-3;

using veci = std::vector<int >;
using vecd = std::vector<double >;


template<class T >
T pp(T x){
    return x * x;
}

template<class T >
T ppp(T x){
    return x * x * x;
}

Eigen::Vector2f Evaluate(std::vector<Eigen::Vector2f> A, double u)
{
    int n=A.size()-1;
    for(int i=0;i<n;++i)
    {
        for(int j=0;j<n-i;++j)
            A[j] = (1.0-u)*A[j]+u*A[j+1];
    }
    return A[0];
}

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
}


void Widget::mouseReleaseEvent(QMouseEvent *event) {
    qDebug()<<"mouseRelease";
  if(event->button() == Qt::RightButton){
      // 初始化生成曲线
       initSpline();
  }
  else if(event->button() == Qt::LeftButton){

    QPoint clickPosition = event->pos();
    int clickX = clickPosition.x();
    int clickY = clickPosition.y();
    ControlPoint* controlt = new ControlPoint(this);
    controlt->setMiddle(clickX, clickY);
    cp.push_back(controlt);
    controlt->show();
  }else if(event->button()==Qt::MidButton){
      for(int i=0;i<cp.size();++i) delete(cp[i]);
      cp.clear();
      update();
  }
}

void Widget::mouseDoubleClickEvent(QMouseEvent *event)
{
}

bool Widget::eventFilter(QObject *watched, QEvent *event)  {
//qDebug()<<event->type();
           if (event->type() == QEvent::Move) {
               bezier();
           } else if (event->type() == QEvent::Resize) {
               bezier();
           }
       return QObject::eventFilter(watched, event);
}

void Widget::paintEvent(QPaintEvent *event){
  QWidget::paintEvent(event);
  QPainter painter(this);

  // 绘制图例
  painter.setPen(Qt::green);
  painter.drawLine(10, 10, 50, 10);
  painter.setPen(Qt::black);
  painter.drawText(60, 15, "三次样条");


  painter.setPen(Qt::green);
  while(!lines.empty()) {
      auto f=lines.front();
      lines.pop();
      //qDebug()<<f.first.x()<<f.first.y();
      painter.drawLine(f.first, f.second);
  }
}



// 初始化贝塞尔控制点
void Widget::initSpline()
{
    if(cp.size()<2)return;
    cp[0]->setRight(0, -30);
    cp.back()->setRight(0, 30);
    for(int i=1;i<cp.size()-1;++i) {
        auto m = cp[i+1]->getMiddle() - cp[i-1]->getMiddle();
        cp[i]->setRight(m.x()/6, m.y()/6);
    }

    for(int i=0;i<cp.size();++i) {
        cp[i]->installEventFilter(this);
    }

    bezier();
}

void Widget::bezier()
{
    qDebug()<<"bezier";
    if(cp.size()<2)return;
    bool first=true;
    std::vector<Eigen::Vector2f> ctrls(4);
    Eigen::Vector2f pre(cp[0]->getMiddle().x(), cp[0]->getMiddle().y());
    for(int i=0;i<cp.size()-1;++i) {
        Eigen::Vector2f p0(cp[i]->getMiddle().x(), cp[i]->getMiddle().y());
        Eigen::Vector2f p1(cp[i+1]->getMiddle().x(), cp[i+1]->getMiddle().y());        

        Eigen::Vector2f d0(cp[i]->getRight().x(), cp[i]->getRight().y());
        Eigen::Vector2f d1(cp[i+1]->getLeft().x(), cp[i+1]->getLeft().y());
        ctrls[0] = p0;
        ctrls[1] = p0 + d0;
        ctrls[2] = p1 + d1;
        ctrls[3] = p1;
        for(double t=0;t<1;t+=0.01) {
            Eigen::Vector2f P = Evaluate(ctrls, t);
            if(!first)lines.push({QPoint(pre.x(), pre.y()), QPoint(P.x(), P.y())});
            first=false;
            pre=P;
        }
    }

    update();
}


Widget::~Widget()
{
    delete ui;
}

